package com.cloudea.lotus;

import com.cloudea.lotus.action.LotusAction;
import com.cloudea.lotus.action.LotusActionLogin;
import com.cloudea.lotus.common.TokenManager;
import com.cloudea.lotus.dao.DAO;
import com.cloudea.lotus.dao.MySQLConfig;
import com.cloudea.lotus.dao.MySQLConnector;
import com.cloudea.lotus.dao.MySQLDAO;
import com.cloudea.lotus.lambda.LotusLambdaExtend;
import com.cloudea.lotus.lambda.LotusLambdaFilter;
import com.cloudea.lotus.lambda.LotusLambdaImpl;
import com.cloudea.lotus.utils.JWTUtil;
import com.cloudea.lotus.utils.StringUtil;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

public class Lotus {
    private static Logger logger = Logger.getLogger(Lotus.class);


    public static void main(String[] args) {
        int argSize = (args.length);
        logger.debug("命令行参数数量： " + argSize);


        // 选项预读
        Map<String, String> argsMap = new HashMap<>();
        for(int i = 0; i < argSize; i++){
            String arg = args[i];
            String[] frags = arg.split("=", 2);
            if(frags.length != 2){
                argsMap.put(arg, "");
            }else{
                argsMap.put(frags[0], frags[1]);
            }
        }
        logger.trace("输入选项" + argsMap.toString());

        // -H
        if(argsMap.containsKey("-H") || argsMap.containsKey("--help")){
            printCMD();
        }

        // -M 参数
        MySQLConfig mySQLConfig = new MySQLConfig();
        mySQLConfig.setDbPath("localhost:3306");
        mySQLConfig.setDbName("lotus");
        mySQLConfig.setDbUser("lotus");
        mySQLConfig.setDbPass("lotus");
        if(argsMap.containsKey("-M")){
            String mysqlPrams = argsMap.get("-M");
            logger.trace("使用MySQL：" + mysqlPrams);
            String[] frags = mysqlPrams.split("/");
            if(frags.length != 4){
                logger.error("mysql格式不正确");
                printCMD();
                System.exit(-1);
            }
            mySQLConfig.setDbPath(frags[0]);
            mySQLConfig.setDbName(frags[1]);
            mySQLConfig.setDbUser(frags[2]);
            mySQLConfig.setDbPass(frags[3]);
        }

        // -U 参数判定
        boolean generateRBAC = argsMap.get("-U") != null && argsMap.get("-U").equals("");
        logger.trace("是否使用生成RBAC表：" + generateRBAC);

        // -P 参数判定
        int port = 8080;
        if(argsMap.containsKey("-P")){
            try{
                port = Integer.parseInt(argsMap.get("-P"));
            }catch (NumberFormatException e){
                logger.error("端口号必须是1~65535之间", e);
                System.exit(-1);
            }
        }

        // 进行初始，如遇输入的mysql、redis不能正常连接，程序也不能启动
        init(mySQLConfig, generateRBAC, port, new LinkedList<>());
    }

    public static void init(MySQLConfig mySQLConfig, boolean generateRBAC, int port, List<LotusAction> extracActions){
        logger.info("程序开始启动");
        MySQLConnector mySQLConnector = new MySQLConnector(mySQLConfig);
        try {
            //MYSQL 连接测试
            Connection connection = mySQLConnector.connect();
            connection.close();
        } catch (SQLException throwables) {
            logger.error("无法连接到数据库", throwables);
            System.exit(-1);
        }

        if(generateRBAC){
            DAO mySQLDAO = new MySQLDAO(mySQLConnector);
            boolean isNotDeedCreateTable = mySQLDAO.has("_user")
                    && mySQLDAO.has("_role")
                    && mySQLDAO.has("_tran")
                    && mySQLDAO.has("_user_role")
                    && mySQLDAO.has("_role_tran");
            //创建表
            if(!isNotDeedCreateTable){
                logger.info("发现没有合适的表结构");
                logger.info("正在创建表结构");
                InputStream inputStream = null;
                try {
                    inputStream = Lotus.class.getResource("/mysql.sql").openStream();
                } catch (IOException e) {
                    logger.error("无法打开mysql.sql文件", e);
                    System.exit(-1);
                }
                String sqlBatch = null;
                try {
                    sqlBatch = StringUtil.streamToString(inputStream);
                } catch (Exception e) {
                    logger.error("无法读取SQL语句", e);
                    System.exit(-1);
                }
                if(!mySQLDAO.execute(sqlBatch)){
                    logger.error("表结构创建失败");
                    System.exit(-1);
                }
                logger.info("表结构创建完毕");
            }else{
                logger.info("已经有合适的表解构, 不需要再建表（未对字段任详细检验，因此也可能令系统正常运行）");
            }
        }

        //TOKEN Manager(public key manager!)
        List<String> staticTokens = new LinkedList<>();
        staticTokens.add(JWTUtil.getPublicKey());
        TokenManager tokenManager = new TokenManager(staticTokens);
        logger.info("本机key：" + JWTUtil.getPublicKey());
        logger.info("存在的keys：" + staticTokens);

        //添加路由
        DAO mySQLDAO = new MySQLDAO(mySQLConnector);
        List<String> tableNames = mySQLDAO.getTables();
        Server server = new Server(port);
        for(String tableName : tableNames){
            LotusLambdaImpl lotusLambda = new LotusLambdaImpl(tableName, mySQLDAO);
            LotusLambdaFilter filter = new LotusLambdaFilter(lotusLambda, tokenManager);
            server.addContext(tableName, filter);
        }

        //额外的路由:登录
        LotusLambdaExtend lotusLambdaExtend = new LotusLambdaExtend(mySQLDAO);
        if(generateRBAC){
            LotusAction logiAction = new LotusActionLogin();
            lotusLambdaExtend.addAction(logiAction.getName(), logiAction);
        }

        // 其它额外路由
        if(extracActions != null){
            for(LotusAction action : extracActions){
                lotusLambdaExtend.addAction(action.getName(), action);
            }
        }

        server.addContext("", lotusLambdaExtend);
        server.start();
    }

    public static void printCMD(){
        String msg ="输入格式：  本程序 [-H] [-M=<mysql>] [-U] [-P=<port>] \n" +
                "选项解释： \n" +
                "-H            - 打印帮助\n" +
                "-M            - 指定mysql， 默认是localhost:3306/lotus/lotus/lotus\n" +
                "-U            - 指明创建用户权限信息，启上此项后，会在数据库中自动创建符合RBAC的权限表，并且系统程序支持使用 /login 进行登录 \n" +
                "-P=<port>     - 指定程序运行的端口号，默认为8080\n" +
                "参数解释： \n" +
                "port          - 运行的端口号，例如 8080 \n" +
                "mysql         - 例如 127.0.0.2:8080/dbPath/dbUser/dbPass \n";
        logger.error("你输入的参数有误！");
        logger.info(msg);
    }
}
